HOME/Articles/

Tacometer (1)

Article Outline

Example Python program Tacometer (1).py This program creates a PyQt GUI

Modules

  • import math
  • from PyQt5.QtCore import QObject, QSize, QPointF, Qt, QRect, QPoint
  • from PyQt5.QtGui import QPainter, QColor, QPen, QRadialGradient, QBrush, QPolygon, QFont, QPainterPath
  • from AbstractMeter import AbstractMeter
  • import sys
  • import random
  • from PyQt5.QtWidgets import QApplication
  • from PyQt5.QtCore import QTimer

Classes

  • class TacoMeterPrivate(QObject):
  • class TacoMeter(AbstractMeter):

Methods

  • def init(self, q):
  • def draw_background(self, painter):
  • def draw_value(self, painter):
  • def initCoordinateSystem(self, painter):
  • def init(self, parent=None):
  • def sizeHint(self):
  • def draw_background(self, painter):
  • def draw_value(self, painter):

Code

Example Python PyQt program :

# -*- coding: utf-8 -*-

import math
from PyQt5.QtCore import QObject, QSize, QPointF, Qt, QRect, QPoint
from PyQt5.QtGui import QPainter, QColor, QPen, QRadialGradient, QBrush, QPolygon, QFont, QPainterPath

from AbstractMeter import AbstractMeter


class TacoMeterPrivate(QObject):
    def __init__(self, q):
        QObject.__init__(self)
        self.mPointer = q

        self.mDigitFont = QFont()
        self.mDigitFont.setPointSizeF(18)

        self.mValueFont = QFont()
        self.mValueFont.setPointSizeF(22)

        self.mDigitOffset = 105.0

        self.mValueOffset = -100

    def draw_background(self, painter):
        self.initCoordinateSystem(painter)

        pen = QPen(QColor(0, 0, 0))
        pen.setWidth(4)
        painter.setPen(pen)

        back1 = QRadialGradient(QPointF(0.0, 0.0), 180.0, QPointF(-35.0, 145.0))
        back1.setColorAt(0.0, QColor(250, 250, 250))
        back1.setColorAt(1.0, QColor(20, 20, 20))

        back2 = QRadialGradient(QPointF(0.0, 0.0), 225.0, QPointF(76.5, 135.0))
        back2.setColorAt(0.0, QColor(10, 10, 10))
        back2.setColorAt(1.0, QColor(250, 250, 250))

        painter.setBrush(QBrush(back1))
        painter.drawEllipse(-162, -162, 324, 324);
        painter.setPen(Qt.NoPen)
        painter.setBrush(QBrush(back2))
        painter.drawEllipse(-152, -152, 304, 304)

        shield = QRadialGradient(QPointF(0, 0), 182, QPointF(-12.0, -15.0))
        shield.setColorAt(0.0, Qt.white)
        shield.setColorAt(0.5, QColor(240, 240, 240))
        shield.setColorAt(1.0, QColor(215, 215, 215))

        painter.setBrush(QBrush(shield))
        painter.setPen(pen)
        painter.drawEllipse(-142, -142, 284, 284)

        painter.setPen(Qt.NoPen)

        painter.setBrush(QColor(0, 200, 0))
        angle = int((3840 * (self.mPointer.nominal() - self.mPointer.minimal())) / (
            self.mPointer.maximal() - self.mPointer.minimal()))
        painter.drawPie(QRect(-141, -141, 282, 282), -480, 3840 - angle % 5760)

        painter.setBrush(QBrush(Qt.red))
        angle = int((3840 * (self.mPointer.critical() - self.mPointer.minimal())) / (
            self.mPointer.maximal() - self.mPointer.minimal()))
        painter.drawPie(QRect(-141, -141, 282, 282), -480, 3840 - angle % 5760)

        painter.setBrush(QBrush(shield))
        painter.drawEllipse(-129, -129, 258, 258)

        painter.rotate(60)

        painter.save()
        painter.setBrush(QBrush(Qt.black))
        line_length = 10
        scaleTriangle = [QPoint(-6, 141), QPoint(6, 141), QPoint(0, 129)]

        for i in range(33):
            painter.setPen(pen)
            if i % 4:
                painter.drawLine(0, 140, 0, 140 - line_length)
            else:
                painter.setPen(Qt.NoPen)
                painter.drawConvexPolygon(QPolygon(scaleTriangle))

            painter.rotate(7.5)
            pen.setWidth(3)

            if i % 2:
                line_length = 10
            else:
                line_length = 5

        painter.restore()

        painter.setPen(Qt.black)
        painter.rotate(-60.0)
        painter.setFont(self.mDigitFont)

        for i in range(9):
            v = self.mPointer.minimal() + i * (self.mPointer.maximal() - self.mPointer.minimal()) / 8.0
            if abs(v) < 0.000001:
                v = 0.0
            val = "{}".format(v)
            Size = painter.fontMetrics().size(Qt.TextSingleLine, val)
            painter.save()
            painter.translate(self.mDigitOffset * math.cos((5 + i) * math.pi / 6.0),
                              self.mDigitOffset * math.sin((5 + i) * math.pi / 6.0))
            painter.drawText(QPointF(Size.width() / -2.0, Size.height() / 4.0), val)
            painter.restore()

    def draw_value(self, painter):
        self.initCoordinateSystem(painter)
        hand = [-4, 0, -1, 129, 1, 129, 4, 0, 8, -50, -8, -50]

        hand_path = QPainterPath()
        hand_path.moveTo(QPointF(hand[0], hand[1]))

        for i in range(2, 10, 2):
            hand_path.lineTo(hand[i], hand[i + 1])

        hand_path.cubicTo(8.1, -51.0, 5.0, -48.0, 0.0, -48.0)
        hand_path.cubicTo(-5.0, -48.0, -8.1, -51.0, -8.0, -50.0)

        painter.save()

        painter.rotate(60.0)
        painter.setPen(Qt.NoPen)
        painter.setBrush(QBrush(Qt.black))
        painter.rotate(((self.mPointer.value() -
                         self.mPointer.minimal()) * 240.0) / (self.mPointer.maximal() - self.mPointer.minimal()))

        painter.drawPath(hand_path)

        painter.drawEllipse(-10, -10, 20, 20)

        painter.restore()

        if self.mPointer.value() >= self.mPointer.critical():
            painter.setPen(Qt.red)

        painter.setFont(self.mValueFont)
        st = "{0:.4g} %".format(self.mPointer.value())
        Size = painter.fontMetrics().size(Qt.TextSingleLine, st)
        painter.drawText(QPointF(Size.width() / -2, -self.mValueOffset), st)
        painter.end()

    def initCoordinateSystem(self, painter):
        side = min(self.mPointer.width(), self.mPointer.height())
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(self.mPointer.width() / 2, self.mPointer.height() / 2)
        painter.scale(side / 335.0, side / 335.0)


class TacoMeter(AbstractMeter):
    def __init__(self, parent=None):
        AbstractMeter.__init__(self, parent=parent)
        self.dPtr = TacoMeterPrivate(self)
        self.value_background = False

    def sizeHint(self):
        return QSize(300, 300)

    def draw_background(self, painter):
        self.dPtr.draw_background(painter)

    def draw_value(self, painter):
        self.dPtr.draw_value(painter)


if __name__ == '__main__':
    import sys
    import random

    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtCore import QTimer

    app = QApplication(sys.argv)
    w = TacoMeter()
    timer = QTimer()
    timer.timeout.connect(lambda : w.setValue(random.uniform(0, 100)))
    timer.start(1000)
    w.show()
    sys.exit(app.exec_())